package com.whz.governance.utils;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import com.alibaba.nacos.api.exception.NacosException;
import com.whz.generic.spring.SpringUtils;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;

/**
 * nacos config utils
 *
 * @author whz
 */
@Slf4j
@UtilityClass
public class NacosConfigUtils {

    /**
     * Get config.
     *
     * @param dataId    dataId
     * @param group     group
     * @param timeoutMs read timeout
     * @return config value
     */
    public static String getConfig(String dataId, String group, long timeoutMs) {
        return getServer().map(server -> getConfig(dataId, group, timeoutMs, server)).orElse("");
    }


    private static String getConfig(String dataId, String group, long timeoutMs, ConfigService server) {
        try {
            return server.getConfig(dataId, group, timeoutMs);
        } catch (NacosException e) {
            log.error("getConfig->dataId=" + dataId + ",group=" + group, e);
        }
        return null;
    }


    /**
     * Get config which will be deserialized to Object.
     *
     * @param dataId    dataId
     * @param group     group
     * @param timeoutMs read timeout
     * @return config value
     */
    public static <T> T getConfigObject(String dataId, String group, long timeoutMs) {
        return GenericObjectUtils.stringToObj(getConfig(dataId, group, timeoutMs));
    }

    /**
     * Publish config.
     *
     * @param dataId  dataId
     * @param group   group
     * @param content content
     * @param type    config type {@link ConfigType}
     * @return Whether publish
     */
    public static boolean publishConfig(String dataId, String group, String content, ConfigType type) {
        return getServer().map(server -> publishConfigInner(dataId, group, content, type, server)).orElse(false);
    }

    private static boolean publishConfigInner(String dataId, String group, String content, ConfigType type,
                                              ConfigService server) {
        try {
            return server.publishConfig(dataId, group, content, type.getType());
        } catch (NacosException e) {
            log.error("publishConfig->dataId=" + dataId + ",group=" + group, e);
        }
        return false;
    }


    /**
     * publish object which will be serialized by jdk and encoded with BASE64  to Nacos config
     *
     * @param dataId  dataId
     * @param group   group
     * @param content content which can be serializable
     * @return Whether publish
     */
    public static boolean publishConfigObject(String dataId, String group, Object content) {
        return publishConfig(dataId,
                             group,
                             GenericObjectUtils.objToString(content),
                             ConfigType.TEXT);
    }

    /**
     * Remove config.
     *
     * @param dataId dataId
     * @param group  group
     * @return whether remove
     */
    public static boolean removeConfig(String dataId, String group) {
        return getServer().flatMap(server -> {
            try {
                return Optional.of(server.removeConfig(dataId, group));
            } catch (NacosException e) {
                log.error("publishConfig->dataId=" + dataId + ",group=" + group, e);
            }
            return Optional.empty();
        }).orElse(false);
    }

    private static Optional<ConfigService> getServer() {
        return SpringUtils.getBean(ConfigService.class);
    }
}
